use bytes::Bytes;
use carpet::base::{
    dto::{FileContent, FileItem},
    param::Multipart,
};
use js_sys::Uint8Array;
use leptos::{ev, prelude::*, task::spawn_local};
use serde::{Deserialize, Serialize};
use template_api::api::demo::file::*;
use thaw::{Button, FileList, Icon, Popover, PopoverTrigger, Scrollbar, Space, Toast, ToastBody, ToasterInjection, Upload, UploadDragger};
use thaw_utils::mount_style;
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::JsFuture;
use web_sys::Blob;
use crate::{components::title_bar::TitleBar, state::ClientManager, tauri::{invoke, is_tauri_env, to_js_value}};
use leptos_drag_reorder::{
    provide_drag_reorder, use_drag_reorder, HoverPosition, UseDragReorderReturn,
};

async fn blob_to_bytes(blob: Blob) -> Result<Bytes, JsValue> {
    let array_buffer_promise = blob.array_buffer();
    let array_buffer = JsFuture::from(array_buffer_promise).await?;
    let uint8_array = Uint8Array::new(&array_buffer);
    let mut bytes_vec = vec![0; uint8_array.length() as usize];
    uint8_array.copy_to(&mut bytes_vec[..]);
    Ok(Bytes::from(bytes_vec))
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CreateWindowOption {
    pub label: String,
    pub title: String,
    pub path: String,
}

#[component]
pub fn Email() -> impl IntoView {
    let toaster = ToasterInjection::expect_context();

    let custom_request = move |file_list: FileList| {
        let len = file_list.length();
        let file = file_list.get(0);

        toaster.dispatch_toast(
            move || {
                view! {
                    <Toast>
                        <ToastBody>{format!("上传的文件数: {len}")}</ToastBody>
                    </Toast>
                }
            },
            Default::default(),
        );

        spawn_local(async move {
            let Some(file) = file else {
                return;
            };
            let content = file.slice().unwrap();
            let content = blob_to_bytes(content).await.unwrap();

            let client: HandleClient<_, _> = ClientManager::get_client();
            let response = client._handle(Multipart(RequestData {
                title: String::from("title"),
                age: Some(1),
                description: vec![String::from("description")],
                image: FileItem {
                    content: FileContent {
                        bytes: content,
                    },
                    file_name: Some(String::from("file_name")),
                    content_type: Some(String::from("application/text")),
                },
            })).await.unwrap();
            let response = response.text().await.unwrap();
            toaster.dispatch_toast(
                move || {
                    view! {
                        <Toast>
                            <ToastBody>{response}</ToastBody>
                        </Toast>
                    }
                },
                Default::default(),
            );
        });
    };
    
    let create_window = move |_| {
        if is_tauri_env() {
            spawn_local(async move {
                invoke("create_window", to_js_value(&CreateWindowOption { label: String::from("test"), title: String::from("test-title"), path: "/login".into() }).unwrap()).await;
            });
        } else {
            window().open_with_url_and_target( "https://www.taobao.com/","_blank").unwrap();
        }
    };
    
    view! {
        <TitleBar>
            <div
                on:click=create_window
                class="h-full w-[40px] flex justify-center items-center hover:bg-gray-200"
            >
                <Icon icon=icondata::VsGear />
            </div>
        </TitleBar>
        <div class="flex-grow">
            <div>
                <Scrollbar>
                    <Space>
                        <p>"邮件"</p>
                        <Upload custom_request multiple=false accept="text/plain">
                            <UploadDragger>"点击或拖拽文件到该位置上传"</UploadDragger>
                        </Upload>
                        <Popover>
                            <PopoverTrigger slot>
                                <Button>"悬停"</Button>
                            </PopoverTrigger>
                            "Content"
                        </Popover>
                        {move || {
                            if is_tauri_env() {
                                view! {
                                    <div data-tauri-drag-region class="title flex">
                                        "拖动"
                                    </div>
                                }
                                    .into_any()
                            } else {
                                ().into_any()
                            }
                        }}
                    </Space>
                    <DragPanelDemo />
                </Scrollbar>
            </div>
        </div>
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
struct PanelInfo {
    id: u32,
    title: String,
}

#[component]
fn DragPanelDemo() -> impl IntoView {
    mount_style("dragpanle", include_str!("./demo.css"));

    let panels = RwSignal::new(vec![
        PanelInfo {
            id: 1,
            title: "Panel #1".to_string(),
        },
        PanelInfo {
            id: 2,
            title: "Panel #2".to_string(),
        },
        PanelInfo {
            id: 3,
            title: "Panel #3".to_string(),
        },
    ]);
    let panel_order = [
        // Column 1
        RwSignal::new(vec!["1".into(), "3".into()]),
        // Column 2
        RwSignal::new(vec!["2".into()]),
    ];
    let column_refs = provide_drag_reorder(panel_order);

    let columns = panel_order
        .into_iter()
        .zip(column_refs)
        .map(|(ordering, column_ref)| {
            let column_items = move || {
                ordering
                    .read()
                    .iter()
                    .filter_map(|id| {
                        panels
                            .read()
                            .iter()
                            .find(|panel| &panel.id.to_string() == id)
                            .cloned()
                    })
                    .collect::<Vec<_>>()
            };

            view! {
                <div node_ref=column_ref class="column">
                    <For each=column_items key=|item| item.id let:panel>
                        <DragablePanel id=panel.id title=panel.title />
                    </For>
                </div>
            }
        })
        .collect_view();

    let add_panel = {
        move |_: ev::MouseEvent| {
            let mut panels = panels.write();
            let next_id = panels.last().map(|item| item.id).unwrap_or(0) + 1;
            panels.push(PanelInfo {
                id: next_id,
                title: format!("Panel #{next_id}"),
            });
            panel_order[0].update(|order| {
                order.insert(0, next_id.to_string().into());
            });
        }
    };

    view! {
        <div class="root">
            <button on:click=add_panel>"Add Panel"</button>

            <div class="row">{columns}</div>
        </div>
    }
}

#[component]
fn DragablePanel(id: u32, title: String) -> impl IntoView {
    let UseDragReorderReturn {
        node_ref,
        draggable,
        set_draggable,
        hover_position,
        on_dragstart,
        on_dragend,
        ..
    } = use_drag_reorder(id.to_string());

    view! {
        <div
            node_ref=node_ref
            class="panel"
            class=(
                "panel--above",
                move || matches!(hover_position.get(), Some(HoverPosition::Above)),
            )
            class=(
                "panel--below",
                move || matches!(hover_position.get(), Some(HoverPosition::Below)),
            )
            draggable=move || draggable.get().then_some("true")
            on:dragstart=on_dragstart
            on:dragend=on_dragend
            on:mousedown=move |_| set_draggable(true)
        >
            {title}
        </div>
    }
}